//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.ManagementStudioControls.RegistryManagerModule
{
    using System;
    using System.ComponentModel;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Windows;
    using Microsoft.Research.ScientificWorkflow.UIDesigner.WpfComposite;
    using Microsoft.Practices.Unity;
    using ManagementStudioServices.Interfaces;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;
    using System.Collections.ObjectModel;
    using System.IO;
    using Microsoft.Win32;
    using Microsoft.Research.ScientificWorkflow.ManagementStudioControls.Common;
    using Microsoft.Research.ScientificWorkflow.ManagementStudioModels;
    using Microsoft.Research.ScientificWorkflow.UIDesigner;
    using Microsoft.Research.ScientificWorkflow.TridentModel;
    using System.Windows.Input;
    using System.Globalization;
    using System.Workflow.ComponentModel.Compiler;
    using SR = Microsoft.Research.DataLayer;
    using Microsoft.Research.ScientificWorkflow.SecurityControls;
    using Microsoft.Research.eResearch.Common.Linq;
    using System.Windows.Controls;
    
    /// <summary>
    /// Workflow Catalog CenterPane Presenter
    /// </summary>
    public class WorkflowCenterPanePresenter : IRegistryManagerCenterPanePresenter, INotifyPropertyChanged
    {
        private WorkflowCatalogViewModel selectedModel;

        private WorkflowCatalogViewModel editableWorkflowModel;

        private IUnityContainer container;

        private IRegistryManagerService registryManagerService;

        private CategoryViewModel categoryPickerSelectedModel;

        private CategoryPicker categoryPicker;

        private UIHelper uiHelper;

        private bool saveInProgress;

        private bool showWorkflowDetails;

        private bool showPackaging;

        /// <summary>
        /// A control that indicates that there is some work happening in the background.
        /// </summary>
        private WaitControl waitControl;

        /// <summary>
        /// Gets or sets the browse image command.
        /// </summary>
        /// <value>The browse image command.</value>
        public DelegateCommand<object> BrowseImageCommand { get; set; }

        /// <summary>
        /// Gets or sets the browse category command.
        /// </summary>
        /// <value>The browse category command.</value>
        public DelegateCommand<object> BrowseCategoryCommand { get; set; }

        /// <summary>
        /// Gets or sets the UpdateCommand command.
        /// </summary>
        /// <value>The browse category command.</value>
        public DelegateCommand<BaseRegMgrModel> UpdateCommand { get; set; }

        /// <summary>
        /// Gets or sets the save category changes command.
        /// </summary>
        /// <value>The save category changes command.</value>
        public DelegateCommand<object[]> SaveWorkflowCommand { get; set; }

        /// <summary>
        /// Gets or sets the select root command.
        /// </summary>
        /// <value>The select root command.</value>
        public DelegateCommand<object> SelectRootCommand { get; set; }

        /// <summary>
        /// Gets or sets the cancel category changes command.
        /// </summary>
        /// <value>The cancel category changes command.</value>
        public DelegateCommand<object> CancelWorkflowChangesCommand { get; set; }

        /// <summary>
        /// Gets or sets the Package Command.
        /// </summary>
        /// <value>The cancel category changes command.</value>
        public DelegateCommand<object> PackageCommand { get; set; }

        /// <summary>
        /// Import activity command.
        /// </summary>
        public DelegateCommand<object> NewWorkflowCommand { get; set; }

        /// <summary>
        /// Gets or sets the delete category command.
        /// </summary>
        /// <value>The delete category command.</value>
        public DelegateCommand<object> DeleteWorkflowCommand { get; set; }

        /// <summary>
        /// Gets or sets the Import Workflow command.
        /// </summary>
        /// <value>The delete category command.</value>
        public DelegateCommand<object> ImportWorkflowCommand { get; set; }

        /// <summary>
        /// Gets or sets the delete category command.
        /// </summary>
        /// <value>The delete category command.</value>
        public DelegateCommand<BaseRegMgrModel> DeleteCommand { get; set; }

        /// <summary>
        /// Gets or sets the launch acl command.
        /// </summary>
        /// <value>The launch acl command.</value>
        public DelegateCommand<object> LaunchAclCommand { get; set; }

        /// <summary>
        /// Gets or sets the browse image command.
        /// </summary>
        /// <param name="container">The container.</param>
        /// <param name="contentView">The content view.</param>
        /// <param name="service">The service.</param>
        /// <value>The browse image command.</value>
        public WorkflowCenterPanePresenter(IUnityContainer container, WorkflowCatalogCenterPane contentView, IRegistryManagerService service)
        {
            this.container = container;
            contentView.DataContext = this;
            this.ContentView = contentView;
            this.registryManagerService = service;
            this.container = container;
            this.registryManagerService = service;
            this.BrowseCategoryCommand = new DelegateCommand<object>(p => this.BrowseCategoryExecute());
            this.SaveWorkflowCommand = new DelegateCommand<object[]>(this.SaveWorkflowChangesExecute);
            this.CancelWorkflowChangesCommand = new DelegateCommand<object>(p => this.CancelWorkflowChangesExecute());
            this.BrowseImageCommand = new DelegateCommand<object>(p => this.BrowseImageExecute());

            this.NewWorkflowCommand = new DelegateCommand<object>(p => this.NewWorkflowCommandExecute());
            this.ImportWorkflowCommand = new DelegateCommand<object>(p => this.ImportWorkflowCommandExecute());
            this.DeleteWorkflowCommand = new DelegateCommand<object>(p => this.DeleteWorkflowCommandExecute(), c => this.CanWorkflowDeleteExecute());

            this.PackageCommand = new DelegateCommand<object>(p => this.PackageCommandExecute());
            this.LaunchAclCommand = new DelegateCommand<object>(p => this.LaunchAclCommandExecute());

            this.uiHelper = new UIHelper(this.registryManagerService.RegistryConnection);
            this.uiHelper.WorkflowImported += new EventHandler<ImportEventArgs>(this.OnWorkflowImported);

            // add handlers for the wait control functionality for import.
            this.uiHelper.AddWaitControl += new EventHandler<WaitMessageEventArgs>(this.OnAddWaitControl);
            this.uiHelper.RemoveWaitControl += new EventHandler<EventArgs>(this.OnRemoveWaitControl);
            this.ShowWorkflowDetailsUI();
        }

        private bool CanWorkflowDeleteExecute()
        {
            bool canDelete = false;
            if (this.selectedModel != null)
            {
                canDelete = this.selectedModel.DeleteAllowed && TridentAuthentication.CanUserDeleteWorkflow(this.selectedModel.OwnerId);
            }

            return canDelete;
        }

        /// <summary>
        /// Saves the changes.
        /// </summary>
        /// <returns>True if save is success.</returns>
        public SaveStateHandler SaveChanges()
        {
            return this.EnforceSaveForChanges();
        }

        #region IRegistryManagerCenterPanePresenter Members

        public UIElement ContentView
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the refresh command.
        /// </summary>
        /// <value>The refresh command.</value>
        public DelegateCommand<BaseRegMgrModel> RefreshCommand { get; set; }

        /// <summary>
        /// Gets or sets the editable category model.
        /// </summary>
        /// <value>The editable category model.</value>
        public WorkflowCatalogViewModel EditableWorkflowModel
        {
            get
            {
                return this.editableWorkflowModel;
            }

            set
            {
                this.editableWorkflowModel = value;
                this.OnNotifyPropertyChanged("EditableWorkflowModel");
            }
        }

        /// <summary>
        /// Gets or sets the selected model.
        /// </summary>
        /// <value>The selected model.</value>
        public BaseRegMgrModel SelectedModel
        {
            get
            {
                return this.selectedModel;
            }
            set
            {
                if (null != this.EditableWorkflowModel && !this.EditableWorkflowModel.Id.Equals(value.Id))
                {
                    this.container.Resolve<IStatusMessageControl>().SetText(string.Empty);
                }
                this.selectedModel = value as WorkflowCatalogViewModel;

                this.InitializeWorkflowDetails();
                this.ShowWorkflowDetailsUI();
                this.EditableWorkflowModel = WorkflowCatalogViewModel.CreateClone(this.selectedModel, this.registryManagerService.GetSystemPolicy());
            }
        }

        /// <summary>
        /// Initializes the workflow details.
        /// </summary>
        private void InitializeWorkflowDetails()
        {
            try
            {
                if (!this.selectedModel.AdditionalInfoLoaded)
                {
                    //this.selectedModel.GetWorkflowDetails();
                    Collection<WorkflowAssembly> libraryList = new Collection<WorkflowAssembly>();
                    Collection<WorkflowParameter> parameterList = new Collection<WorkflowParameter>();

                    this.registryManagerService.GetWorkflowDetails(this.selectedModel, libraryList, parameterList);

                    libraryList.ForEach(libraryModel => this.selectedModel.LibraryList.Add(libraryModel));
                    parameterList.ForEach(parameterModel => this.selectedModel.ParameterList.Add(parameterModel));

                    this.selectedModel.AdditionalInfoLoaded = true;
                }
            }
            catch (TridentCustomException exp)
            {
                TridentMessageBox.ShowTridentErrorMessageBox(exp.Message);
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether [show workflow details].
        /// </summary>
        /// <value><c>true</c> if [show workflow details]; otherwise, <c>false</c>.</value>
        public bool ShowWorkflowDetails
        {
            get
            {
                return this.showWorkflowDetails;
            }
            private set
            {
                this.showWorkflowDetails = value;
                this.OnNotifyPropertyChanged("ShowWorkflowDetails");
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether [show packaging].
        /// </summary>
        /// <value><c>true</c> if [show packaging]; otherwise, <c>false</c>.</value>
        public bool ShowPackaging
        {
            get
            {
                return this.showPackaging;
            }
            private set
            {
                this.showPackaging = value;
                this.OnNotifyPropertyChanged("ShowPackaging");
            }
        }

        #endregion

        /// <summary>
        /// Enforces whether Save is required for the Model 
        /// </summary>
        /// <returns>SaveStateHolder</returns>
        private SaveStateHandler EnforceSaveForChanges()
        {
            SaveStateHandler saveSuccess = new SaveStateHandler(SaveStatus.Valid);
            if (!this.saveInProgress &&
                this.EditableWorkflowModel != null && !this.EditableWorkflowModel.IsDeleted
                && !this.EditableWorkflowModel.Equals(this.SelectedModel as WorkflowCatalogViewModel))
            {
                MessageBoxResult userResult = TridentMessageBox.ShowTridentConfirmationYesNoMessageBox(ManagementStudioResourceManager.GetString("SaveChangesToWorkflow"));
                if (userResult == MessageBoxResult.Yes)
                {
                    this.SaveWorkflowCommand.Execute(new object[] { false, saveSuccess });
                }
                else if (userResult == MessageBoxResult.No)
                {
                    this.Rollback();
                }
            }

            return saveSuccess;
        }

        /// <summary>
        ///  Handler for Category Browse Command.
        /// </summary>
        private void BrowseCategoryExecute()
        {
            try
            {
                this.LaunchCategoryPicker();
                if (this.categoryPickerSelectedModel != null)
                {
                    this.EditableWorkflowModel.Parent = this.categoryPickerSelectedModel;
                }
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleUIException(ex);
                TridentMessageBox.ShowTridentErrorMessageBox("Error in Launching Category Picker");
            }
        }

        /// <summary>
        ///  Handler for Image Browse Command.
        /// </summary>
        private void BrowseImageExecute()
        {
            string fileSelected = string.Empty;

            OpenFileDialog openDialog = new OpenFileDialog();

            // Filters the XOML file in the current Directory.
            openDialog.Filter = "Image Files (*.png, *.jpg, *.jpeg, *.ico, *.bmp)|*.png; *.jpg; *.jpeg; *.ico; *.bmp";

            // SUer should select only one file to open.
            openDialog.Multiselect = false;

            // Checks and promts the user if the file is not present in the directory.
            openDialog.CheckFileExists = true;

            // Check if File Exists in directory Specified.
            openDialog.CheckPathExists = true;

            // Restores the previous Directory the user had selected to Open/Save the file.
            openDialog.RestoreDirectory = true;

            if ((bool)openDialog.ShowDialog())
            {
                // Get the selected file name.
                fileSelected = openDialog.FileName;
            }

            if (!string.IsNullOrEmpty(fileSelected) && File.Exists(fileSelected))
            {
                string selectedExtn = System.IO.Path.GetExtension(fileSelected);
                bool validFile = (selectedExtn.Equals(".png", StringComparison.OrdinalIgnoreCase)
                    || selectedExtn.Equals(".ico", StringComparison.OrdinalIgnoreCase)
                    || selectedExtn.Equals(".jpg", StringComparison.OrdinalIgnoreCase)
                    || selectedExtn.Equals(".jpeg", StringComparison.OrdinalIgnoreCase)
                    || selectedExtn.Equals(".bmp", StringComparison.OrdinalIgnoreCase));
                if (validFile)
                {
                    this.EditableWorkflowModel.IconPath = fileSelected;
                }
                else
                {
                    TridentMessageBox.ShowTridentErrorMessageBox(ManagementStudioResourceManager.GetString("InvalidImageFileSelection"));
                    this.BrowseImageCommand.Execute(null);
                }
            }
        }

        /// <summary>
        /// Handler Cancel command
        /// </summary>
        private void CancelWorkflowChangesExecute()
        {
            this.Rollback();
            if (this.SelectRootCommand != null)
            {
                this.SelectRootCommand.Execute(null);
            }
        }

        /// <summary>
        /// Roll back all changes.
        /// </summary>
        private void Rollback()
        {
            if (this.SelectedModel != null)
            {
                this.EditableWorkflowModel = WorkflowCatalogViewModel.CreateClone(this.SelectedModel as WorkflowCatalogViewModel, this.registryManagerService.GetSystemPolicy());
            }
        }

        /// <summary>
        /// Handler for Delete Workflow command
        /// </summary>
        private void DeleteWorkflowCommandExecute()
        {
            try
            {
                MessageBoxResult res = TridentMessageBox.ShowTridentConfirmationYesNoMessageBox(ManagementStudioResourceManager.GetString("WorkflowDeleteConfirmationMsg"));
                if (res == MessageBoxResult.Yes)
                {
                    this.registryManagerService.DeleteWorkflow(this.editableWorkflowModel);
                    this.editableWorkflowModel.IsDeleted = true;
                    if (this.DeleteCommand != null)
                    {
                        this.DeleteCommand.Execute(this.SelectedModel);
                    }
                }
            }
            catch (TridentCustomException ex)
            {
                TridentErrorHandler.HandleTridentCustomExceptionInUI(ex);
            }
        }

        /// <summary>
        /// Handler for Import Workflow Command
        /// </summary>
        private void ImportWorkflowCommandExecute()
        {
            try
            {
                SaveStateHandler saveState = this.EnforceSaveForChanges();
                if (saveState.SaveOptionSelected != SaveStatus.Invalid)
                {
                    this.uiHelper.ImportWorkflow(this.registryManagerService.RegistryConnection);
                }
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }
        }
        /// <summary>
        /// This event is fired to retrieve the status of the import process for workflow.
        /// </summary>
        /// <param name="sender">sender object</param>
        /// <param name="e">event arguments</param>
        private void OnWorkflowImported(object sender, ImportEventArgs e)
        {
            string message = ManagementStudioResourceManager.GetString("ImportfaliureWorkflow");
            if (!e.Status)
            {
                // Get the error string returned from the exception.
                if (!string.IsNullOrEmpty(e.ErrorMessage))
                    message += e.ErrorMessage;
                TridentMessageBox.ShowTridentErrorMessageBox(Application.Current.MainWindow, message);
            }
            else
            {
                if (this.RefreshCommand != null)
                {
                    this.RefreshCommand.Execute(this.SelectedModel);
                }

                this.container.Resolve<IStatusMessageControl>().SetText(ManagementStudioResourceManager.GetString("ImportSuccessWorkflow"));
            }
        }

        /// <summary>
        /// This function used to add the wait control to the parent grid during the import activity process.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnRemoveWaitControl(object sender, EventArgs e)
        {
            // Get the top-most grid of the main window.
            Grid parentGrid = Application.Current.MainWindow.Content as Grid;
            if (parentGrid != null)
            {
                // Enable all child elements.
                foreach (UIElement element in parentGrid.Children)
                {
                    element.IsEnabled = true;
                }

                // Add the wait control.
                parentGrid.Children.Remove(this.waitControl);
            }
            Application.Current.MainWindow.Cursor = Cursors.Arrow;
        }

        /// <summary>
        /// This function used to remove the wait control after the import of activity completes.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnAddWaitControl(object sender, WaitMessageEventArgs e)
        {
            Application.Current.MainWindow.Cursor = Cursors.Wait;

            // Get the top-most grid of the main window.
            Grid parentGrid = Application.Current.MainWindow.Content as Grid;
            if (parentGrid != null)
            {
                // Create an instance of the wait control.
                if (this.waitControl == null)
                {
                    this.waitControl = new WaitControl(e.WaitMessage);
                    Grid.SetRowSpan(this.waitControl, 3);
                }
                // Disable all existing children in this grid.
                foreach (UIElement element in parentGrid.Children)
                {
                    element.IsEnabled = false;
                }

                // Add the wait control.
                parentGrid.Children.Add(this.waitControl);
            }
            else
            {
                // If parent grid cannot be retrieved, add a wait cursor.
                Application.Current.MainWindow.Cursor = Cursors.Wait;
            }
        }

        /// <summary>
        /// Handler for package Command
        /// </summary>
        private void PackageCommandExecute()
        {
            SaveStateHandler saveState = this.EnforceSaveForChanges();
            if (saveState.SaveOptionSelected != SaveStatus.Invalid)
            {
                PackagingCenterPaneView packagingView = new PackagingCenterPaneView();
                PackagingCenterPanePresenter packagingPresenter = new PackagingCenterPanePresenter(
                    this.container,
                    packagingView,
                    this.uiHelper.WorkflowComposer,
                    this.SelectedModel as WorkflowCatalogViewModel);

                if (packagingPresenter != null)
                {
                    packagingPresenter.Canceled += new EventHandler<EventArgs>(OnPackagingCancelled);
                    packagingView.Presenter = packagingPresenter;
                    packagingView.DataContext = packagingPresenter;

                    WorkflowCatalogCenterPane centerPane = this.ContentView as WorkflowCatalogCenterPane;

                    if (centerPane != null)
                    {
                        centerPane.PackagingHost = packagingView;

                        this.ShowPackagingUI();
                    }
                }
            }
        }

        /// <summary>
        /// Handles the Cancelled event of the packagingPresenter control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void OnPackagingCancelled(object sender, EventArgs e)
        {
            PackagingCenterPanePresenter packagingPresenter = sender as PackagingCenterPanePresenter;

            this.ShowWorkflowDetailsUI();
        }

        /// <summary>
        /// Shows the packaging UI.
        /// </summary>
        private void ShowPackagingUI()
        {
            this.ShowPackaging = true;
            this.ShowWorkflowDetails = false;
        }

        /// <summary>
        /// Shows the workflow details UI.
        /// </summary>
        private void ShowWorkflowDetailsUI()
        {
            this.ShowPackaging = false;
            this.ShowWorkflowDetails = true;
            this.DeleteWorkflowCommand.RaiseCanExecuteChanged();
        }

        /// <summary>
        /// Handler for New Workflow command
        /// </summary>
        private void NewWorkflowCommandExecute()
        {
            try
            {
                this.registryManagerService.OpenComposerForNewWorkflow();
            }
            catch (TridentCustomException ex)
            {
                TridentErrorHandler.HandleTridentCustomExceptionInUI(ex);
            }
            catch (Exception ex)
            {
                TridentErrorHandler.HandleUIException(ex);
            }
        }

        /// <summary>
        /// Handler for Save Command
        /// </summary>
        /// <param name="parameters"></param>
        private void SaveWorkflowChangesExecute(object[] parameters)
        {
            this.saveInProgress = true;
            bool saveSucceeded = false;

            StringBuilder errorMsg = new StringBuilder();
            try
            {
                saveSucceeded = ValidateName();

                if (saveSucceeded)
                {
                    if (this.editableWorkflowModel.AllowLabelEdit && !ValidateLabel())
                    {
                        TridentMessageBox.ShowTridentErrorMessageBox(ManagementStudioResourceManager.GetString("WorkflowLabelInvalid"));
                        return;
                    }
                    else
                    {
                        SR.Activity savedWf = this.registryManagerService.SaveWorkflow(this.EditableWorkflowModel);
                        saveSucceeded = savedWf != null;
                        if (saveSucceeded)
                        {
                            this.EditableWorkflowModel.Update(savedWf);
                            this.EditableWorkflowModel.IsSelected = true;
                        }
                    }
                }
                else
                {
                    errorMsg.AppendLine(ManagementStudioResourceManager.GetString("InvalidWorkflowName"));
                }
            }
            catch (TridentCustomException ex)
            {
                errorMsg.Append(ManagementStudioResourceManager.GetString("SaveWorkflowErrorMsg"));
                if (ex.ErrorNumber.Equals(TridentErrorConstants.ErrorNumber1000000072.ToString(CultureInfo.CurrentCulture)))
                {
                    TridentMessageBox.ShowTridentErrorMessageBox(ex.Message);
                    Environment.Exit(0);
                }
                errorMsg = new StringBuilder();
                errorMsg.Append(" ");
                errorMsg.Append(ex.CustomMessage.ToString());
                saveSucceeded = false;
            }

            if (saveSucceeded)
            {
                if (this.UpdateCommand != null)
                {
                    this.RefreshCommand.Execute(this.EditableWorkflowModel);
                    this.EditableWorkflowModel = WorkflowCatalogViewModel.CreateClone(this.SelectedModel as WorkflowCatalogViewModel, this.registryManagerService.GetSystemPolicy());
                }

                this.container.Resolve<IStatusMessageControl>().SetText(ManagementStudioResourceManager.GetString("SaveSuccessWorkflow"));
            }
            else
            {
                TridentMessageBox.ShowTridentErrorMessageBox(errorMsg.ToString());
            }

            if (parameters != null && parameters.Length > 1)
            {
                SaveStateHandler saveSuccess = parameters[1] as SaveStateHandler;
                saveSuccess.SaveOptionSelected = saveSucceeded ? SaveStatus.Valid : SaveStatus.Invalid;
                if (!saveSucceeded && !this.SelectedModel.IsSelected)
                {
                    WorkflowCatalogViewModel backUpModel = WorkflowCatalogViewModel.CreateClone(this.EditableWorkflowModel, this.registryManagerService.GetSystemPolicy());
                    this.Rollback();
                    this.SelectedModel.IsSelected = true;
                    this.EditableWorkflowModel = WorkflowCatalogViewModel.CreateClone(backUpModel, this.registryManagerService.GetSystemPolicy());
                }
            }

            this.saveInProgress = false;
        }

        /// <summary>
        /// Checks the model is valid for save
        /// </summary>
        /// <param name="saveSucceeded">saveSucceeded</param>
        /// <returns>true if model is valid false other wise</returns>
        private bool ValidateName()
        {
            bool saveSucceeded = true;
            string nameToCheck = this.editableWorkflowModel.Name.Trim();

            if (string.IsNullOrEmpty(nameToCheck) || !TridentWorkflowModel.CheckNameForInvalidCharacters(nameToCheck))
            {
                saveSucceeded = false;
            }

            return saveSucceeded;
        }

        /// <summary>
        /// Launches the category picker
        /// </summary>
        private void LaunchCategoryPicker()
        {
            this.categoryPickerSelectedModel = null;
            CategoryViewModel parentModel = null;
            if (this.SelectedModel != null)
            {
                WorkflowCatalogViewModel currentModel = this.SelectedModel as WorkflowCatalogViewModel;
                parentModel = currentModel.Parent as CategoryViewModel;
            }

            this.categoryPicker = new CategoryPicker(this.container, CategoryType.Workflow, parentModel);
            this.categoryPicker.CategoryPickerOk += new EventHandler<CategoryEventArgs>(this.OnCategoryPickerOk);
            this.categoryPicker.CategoryPickerClose += new EventHandler(this.OnCategoryPickerClose);
            this.categoryPicker.Owner = Application.Current.MainWindow;
            this.categoryPicker.ShowDialog();
        }

        /// <summary>
        /// Event handler for Category Picker OK. 
        /// </summary>
        /// <param name="sender">CategoryPicker</param>
        /// <param name="e">CategoryEventArgs</param>
        private void OnCategoryPickerOk(object sender, CategoryEventArgs e)
        {
            if (e != null && this.EditableWorkflowModel != null)
            {
                CategoryViewModel selectedCategory = e.CategoryPickerSelectedModel;
                if (selectedCategory != null)
                {
                    string errorMsg = string.Empty;
                    bool validSelection = WorkflowCenterPanePresenter.CategorySelectionValidator(this.EditableWorkflowModel, selectedCategory, out errorMsg);
                    if (validSelection)
                    {
                        this.categoryPickerSelectedModel = selectedCategory;
                        this.CloseCategoryPicker();
                    }
                    else if (!string.IsNullOrEmpty(errorMsg))
                    {
                        TridentMessageBox.ShowTridentErrorMessageBox(errorMsg);
                    }
                }
                else
                {
                    TridentMessageBox.ShowTridentErrorMessageBox(ManagementStudioResourceManager.GetString("SelectValidParent"));
                }
            }
        }

        /// <summary>
        /// Event handler for Category picker Close
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnCategoryPickerClose(object sender, EventArgs e)
        {
            this.CloseCategoryPicker();
        }

        /// <summary>
        /// Closes the Category Picker
        /// </summary>
        private void CloseCategoryPicker()
        {
            if (this.categoryPicker != null)
            {
                this.categoryPicker.Close();
                this.categoryPicker = null;
            }
        }

        /// <summary>
        /// Categories the selection validator.
        /// </summary>
        /// <param name="selectedParentModel">The selected parent model.</param>
        /// <param name="errorMsg">The error MSG.</param>
        /// <returns></returns>
        private static bool CategorySelectionValidator(WorkflowCatalogViewModel workflowmodel, CategoryViewModel selectedParentModel, out string errorMsg)
        {
            bool valid = false;
            errorMsg = string.Empty;
            if (selectedParentModel != null)
            {
                StringBuilder errorBuilder = new StringBuilder(ManagementStudioResourceManager.GetString("CategoryPickerInvalidSelection"));
                try
                {
                    valid = WorkflowCenterPanePresenter.CheckRootAssignment(selectedParentModel);
                    if (!valid)
                    {
                        errorBuilder.Append(ManagementStudioResourceManager.GetString("WorkflowCatalogInvalidRootSelection"));
                    }
                }
                catch (Exception ex)
                {
                    TridentErrorHandler.HandleUIException(ex);
                    valid = false;
                    errorBuilder.Append(ex.Message);
                }

                if (!valid)
                {
                    errorMsg = errorBuilder.ToString();
                }
            }

            return valid;
        }

        /// <summary>
        /// Validate the label.
        /// </summary>
        /// <param name="categoryId">The category to which the workflow belongs to.</param>
        /// <param name="label">The workflow label</param>
        /// <param name="workflowName">The workflow name.</param>
        /// <returns>True if the label is valid. False otherwise.</returns>
        private bool ValidateLabel()
        {
            bool result = true;
            string workflowName = this.editableWorkflowModel.Name.Trim();
            string versionLabel = this.editableWorkflowModel.VersionLabel.Trim();

            if (string.IsNullOrEmpty(versionLabel))
            {
                result = false;
            }
            else
            {
                if (!TridentWorkflowModel.CheckNameForInvalidCharacters(versionLabel))
                {
                    result = false;
                }
                else
                {
                    SR.Namespace category = SR.Namespace.Load(this.editableWorkflowModel.Parent.Id, this.registryManagerService.RegistryConnection);
                    Collection<SR.Activity> activities =
                        category.GetWorkflows(workflowName,
                        versionLabel);

                    if (activities != null && activities.Count > 0)
                    {
                        if (activities.Count == 1 && (activities[0] as SR.IObject).ID.Equals(this.editableWorkflowModel.Id))
                        {
                            result = true;
                        }
                        else
                        {
                            result = false;
                        }
                    }
                }
            }
            return result;
        }

        /// <summary>
        /// Checks the root assignment.
        /// </summary>
        /// <param name="selectedParentModel">The selected parent model.</param>
        /// <returns>Validity of assignment</returns>
        private static bool CheckRootAssignment(CategoryViewModel selectedParentModel)
        {
            bool valid = false;
            if (selectedParentModel != null
                && selectedParentModel.RootCategory != null
                && !selectedParentModel.Id.Equals(selectedParentModel.RootCategory.Id))
            {
                valid = true;
            }

            return valid;
        }

        /// <summary>
        /// Launches the acl command execute.
        /// </summary>
        private void LaunchAclCommandExecute()
        {
            if (this.EditableWorkflowModel != null && this.EditableWorkflowModel.CurrentPermissionSettingsModel != null)
            {
                PermissionSettingsCtrl permissionSettingsCtrl = new PermissionSettingsCtrl(
                    this.EditableWorkflowModel.CurrentPermissionSettingsModel,
                    this.registryManagerService.FetchAllEnabledSecurityPrincipals(true));

                permissionSettingsCtrl.ShowInTaskbar = false;
                permissionSettingsCtrl.WindowStartupLocation = WindowStartupLocation.CenterScreen;
                permissionSettingsCtrl.Owner = Application.Current.MainWindow;
                permissionSettingsCtrl.ShowDialog();
                try
                {
                    if (permissionSettingsCtrl.Canceled)
                    {
                        this.EditableWorkflowModel.CurrentPermissionSettingsModel = PermissionSettingsModel.Refresh(this.EditableWorkflowModel.CurrentPermissionSettingsModel, this.registryManagerService.GetSystemPolicy());
                    }
                    else
                    {
                        this.registryManagerService.RegistryConnection.AutoSave = true;
                        this.EditableWorkflowModel.CurrentPermissionSettingsModel.SaveChanges();
                    }
                }
                catch (TridentCustomException ex)
                {
                    TridentErrorHandler.HandleTridentCustomExceptionInUI(ex);
                }
                catch (Exception ex)
                {
                    TridentErrorHandler.HandleKnownExceptionsInUI(ex);
                }
                finally
                {
                    this.registryManagerService.RegistryConnection.AutoSave = false;
                }
            }
        }

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Occurs when a property value changes.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Called by a property when it wants to notify that its value has changed.
        /// </summary>
        /// <param name="propertyName">Name of the property.</param>
        private void OnNotifyPropertyChanged(string propertyName)
        {
            if (this.PropertyChanged != null)
            {
                this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        #endregion
    }
}